/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package app.model_package;

import java.util.ArrayList;
import java.util.HashMap;

/**
 *
 * @author haythem
 */
public class AlphaAlgorithmForProtocol {

    // list of performatives associated to their
    // multiplicity (multiplicity = number of receivers)
    private ArrayList<PerformativeModel> listPerformativeObjects ;

    // list of the performatives as String
    private ArrayList<String> listPerformatives ;

    // list of the conversation IDs
    ArrayList<String> listConversationsID;

    // a hash map of all the conversations that we will manipulate
    HashMap<String,ArrayList<EventModel>> listConversations ;

    // list of initial Performatives
    private ArrayList<String> listInitialPerformatives ;

    // list of final Performatives
    private ArrayList<String> listFinalPerformatives ;

    // list of Performatives related by a sucession relation
    private ArrayList<SuccessionRelation> listSuccessionRelations;

    // list of Performatives related by a causality relation
    private ArrayList<CausalityRelation> listCausalityRelations;

    // list of Performatives related by a choice relation
    private ArrayList<ChoiceRelation> listChoiceRelations;

    // list of relations described in step 4 of the algorithm and also contains
    // the minimal one (step 5)
    private ArrayList<CausalityRelationSetCouple> listCausalityRelationSets;

    // the minimal one (step 5)
//    private ArrayList<CausalityRelationSetCouple> listMinimalCausalityRelationSets;


    // the list of places
    private ArrayList<Place> placesList ;
    // an automatically generated ID for every place
    private Integer id_place;

    /**
     *
     * @param log
     */
    public AlphaAlgorithmForProtocol(LogModel log) {
//        this.log = getOnlyExecutes(log);
        listPerformativeObjects = new  ArrayList<PerformativeModel>();
        listPerformatives = new ArrayList<String>();
        listConversations = new HashMap<String, ArrayList<EventModel>>();
        listConversationsID = new ArrayList<String>();
        listInitialPerformatives = new ArrayList<String>();
        listFinalPerformatives = new ArrayList<String>();
        listSuccessionRelations = new ArrayList<SuccessionRelation>();
        listCausalityRelations = new ArrayList<CausalityRelation>();
        listChoiceRelations = new ArrayList<ChoiceRelation>();
        listCausalityRelationSets = new ArrayList<CausalityRelationSetCouple>();
        placesList = new ArrayList<Place>();
        id_place = 0 ;
        setConversations(log);
//        listMinimalCausalityRelationSets = new ArrayList<CausalityRelationSetCouple>();
    }


    



    ////////////////////////////////////////////////////////////////////
    ///////////////////////// getters and setters /////////////////////
    ///////////////////////////////////////////////////////////////////


    public HashMap<String, ArrayList<EventModel>> getListConversations() {
        return listConversations;
    }

    public void setListConversations(HashMap<String, ArrayList<EventModel>> listConversations) {
        this.listConversations = listConversations;
    }

    public ArrayList<String> getListConversationsID() {
        return listConversationsID;
    }

    public void setListConversationsID(ArrayList<String> listConversationsID) {
        this.listConversationsID = listConversationsID;
    }

    public ArrayList<String> getListFinalPerformatives() {
        return listFinalPerformatives;
    }

    public void setListFinalPerformatives(ArrayList<String> listFinalPerformatives) {
        this.listFinalPerformatives = listFinalPerformatives;
    }

    public ArrayList<String> getListInitialPerformatives() {
        return listInitialPerformatives;
    }

    public void setListInitialPerformatives(ArrayList<String> listInitialPerformatives) {
        this.listInitialPerformatives = listInitialPerformatives;
    }

    public ArrayList<PerformativeModel> getListPerformativeObjects() {
        return listPerformativeObjects;
    }

    public void setListPerformativeObjects(ArrayList<PerformativeModel> listPerformativeObjects) {
        this.listPerformativeObjects = listPerformativeObjects;
    }

    public ArrayList<String> getListPerformatives() {
        return listPerformatives;
    }

    public void setListPerformatives(ArrayList<String> listPerformatives) {
        this.listPerformatives = listPerformatives;
    }



     public Integer getId_place() {
        return id_place;
    }

    public void setId_place(Integer id_place) {
        this.id_place = id_place;
    }


     public ArrayList<Place> getPlacesList() {
        return placesList;
    }

    public void setPlacesList(ArrayList<Place> placesList) {
        this.placesList = placesList;
    }

     public ArrayList<CausalityRelationSetCouple> getListCausalityRelationSets() {
        return listCausalityRelationSets;
    }

    public void setListCausalityRelationSets(ArrayList<CausalityRelationSetCouple> listCausalityRelationSets) {
        this.listCausalityRelationSets = listCausalityRelationSets;
    }

    public ArrayList<CausalityRelation> getListCausalityRelations() {
        return listCausalityRelations;
    }

    public void setListCausalityRelations(ArrayList<CausalityRelation> listCausalityRelations) {
        this.listCausalityRelations = listCausalityRelations;
    }

    public ArrayList<ChoiceRelation> getListChoiceRelations() {
        return listChoiceRelations;
    }

    public void setListChoiceRelations(ArrayList<ChoiceRelation> listChoiceRelations) {
        this.listChoiceRelations = listChoiceRelations;
    }

    public ArrayList<String> getListFinalTasks() {
        return listFinalPerformatives;
    }

    public void setListFinalTasks(ArrayList<String> listFinalTasks) {
        this.listFinalPerformatives = listFinalTasks;
    }

    public ArrayList<String> getListInitialTasks() {
        return listInitialPerformatives;
    }

    public void setListInitialTasks(ArrayList<String> listInitialTasks) {
        this.listInitialPerformatives = listInitialTasks;
    }

//    public ArrayList<CausalityRelationSetCouple> getListMinimalCausalityRelationSets() {
//        return listMinimalCausalityRelationSets;
//    }
//
//    public void setListMinimalCausalityRelationSets(ArrayList<CausalityRelationSetCouple> listMinimalCausalityRelationSets) {
//        this.listMinimalCausalityRelationSets = listMinimalCausalityRelationSets;
//    }

    public ArrayList<SuccessionRelation> getListSuccessionRelations() {
        return listSuccessionRelations;
    }

    public void setListSuccessionRelations(ArrayList<SuccessionRelation> listSuccessionRelations) {
        this.listSuccessionRelations = listSuccessionRelations;
    }

    public ArrayList<PerformativeModel> getListTasks() {
        return listPerformativeObjects;
    }

    public void setListTasks(ArrayList<PerformativeModel> listPerformatives) {
        this.listPerformativeObjects = listPerformatives;
    }

   



    ////////////////////////////////////////////////////////////////////
    /////////////////////////    other methods    /////////////////////
    ///////////////////////////////////////////////////////////////////



    /**
     * this method gets all the performativ and their multiplicity in the
     * conversations
     */
    public void getPerformatives(){
        for (int i=0;i<listConversationsID.size();i++){
            String convID = listConversationsID.get(i);
            ArrayList<EventModel> eventsList = this.listConversations.get((String) convID);
            for (int j=0;j<eventsList.size();j++){
                String performative = eventsList.get(j).getPerfomative();
                boolean multiplicity = (eventsList.get(j).getListReceivers().size()>1);
                // if the performative isn't already added
                if (!this.listPerformatives.contains((String) performative)){
                    this.listPerformatives.add(performative);                    
                    this.listPerformativeObjects.add(new PerformativeModel(performative, multiplicity));
                }
                // if it is added we check its multiplicity if it passes from
                // one to more
                else{
                    int indexPerf = listPerformatives.indexOf((String) performative);
                    if ((multiplicity==true) && (listPerformativeObjects.get(indexPerf).isMultiplicity()==false)){
                        listPerformativeObjects.get(indexPerf).setMultiplicity(true);
                    }
                }
            }
        }
    }

    /**
     * this method have as objective to set the list of the
     * conversations and their IDs from the Log in inputs
     * @param log
     */
    private void setConversations(LogModel log) {
        for (int i=0;i<log.getListCases().size();i++){
            for (int j=0;j<log.getListCases().get(i).getEventsList().size();j++){
                String performative = log.getListCases().get(i).getEventsList().get(j).getPerfomative();
//                if (!performative.equals((String) "execute")){
                
                if (!performative.equals((String) "execute")){
                    String conversationID = log.getListCases().get(i).getEventsList().get(j).getConversationID();
                    if (this.listConversationsID.contains((String) conversationID)){
                        listConversations.get((String) conversationID).add(log.getListCases().get(i).getEventsList().get(j));
                    }
                    else {
                        this.listConversationsID.add(conversationID);
                        this.listConversations.put(conversationID, new ArrayList<EventModel>());
                        this.listConversations.get((String) conversationID).add(log.getListCases().get(i).getEventsList().get(j));
                    }
                }
            }
        }
    }

  

    /**
     * modified
     * this method allows to get the list of initial performatives
     * of all conversations
     */
    public void getInitialPerformatives(){
        for (int i=0;i<this.listConversationsID.size();i++){
            String coversationID = this.listConversationsID.get(i);
            EventModel firstEventInTheConversation = (this.listConversations.get((String) coversationID)).get(0);
            String s = firstEventInTheConversation.getPerfomative();
            if (!listInitialPerformatives.contains((String) s)){
                 this.listInitialPerformatives.add(s);
            }
        }
    }


     /**
      * modified
     * this method allows to get the list of final performatives
     * of all conversations
     */
    public void getFinalPerformatives(){
        for (int i=0;i<this.listConversationsID.size();i++){
            String coversationID = this.listConversationsID.get(i);
            EventModel lastEventInTheConversation = (this.listConversations.get((String) coversationID)).get(this.listConversations.get((String) coversationID).size()-1);
            String s = lastEventInTheConversation.getPerfomative();
            if (!listFinalPerformatives.contains((String) s)){
                 this.listFinalPerformatives.add(s);
            }
        }
    }


  



    /////////////////////////////////////////////////////////
    ////////////////////////// methods /////////////////////
    ////////////////////////////////////////////////////////

   



   

    /**
     * modified
     * this method allows to get all the succession
     * relations in the attribute list of conversations and put them
     * in listSuccessionRelations
     */
    public void buildSuccessionRelationsList(){
        for(int i=0;i<listConversationsID.size();i++){
            String conversationID = listConversationsID.get(i);
            ArrayList<EventModel> eventsList = listConversations.get((String) conversationID);
            for (int j=0;j<eventsList.size()-1;j++){
                String predecessor = eventsList.get(j).getPerfomative();
                String successor =eventsList.get(j+1).getPerfomative();
                // if the SuccessionRelation doesn't already exist we put it into
                // the list
                if (!this.listSuccessionRelationsContains(predecessor, successor)){
                    this.listSuccessionRelations.add(new SuccessionRelation(predecessor, successor));
                }
            }
        }
    }



    /**
     * checks if listSuccessionRelations contains a SuccesionRelation
     * with attributes mentionend in the parameters
     * @param predecessor
     * @param successor
     * @return
     */
    public boolean listSuccessionRelationsContains(String predecessor, String successor){
        boolean b = false ;
        int i = 0 ;
        while ((i<this.listSuccessionRelations.size()) && (b==false)){
            b = this.listSuccessionRelations.get(i).equals(predecessor, successor);
            if (b==false) i++ ;
        }
        return b ;
    }


    /**
     * to fill the list that insure the following relation
     * Causality: x->y if x>y and not y>x
     */
    public void buildCausalityRelationsList(){
        // check all the SeccessRelation objects in the list that is supposed
        // to be
        for (int i=0;i<this.listSuccessionRelations.size();i++){
            String predecessor = this.listSuccessionRelations.get(i).getPredecessorX();
            String successor = this.listSuccessionRelations.get(i).getSuccessorY();
            int j = 0 ;
            boolean b = false ;
            while ((j<this.listSuccessionRelations.size()) && (b==false)){
                if (i!=j){
                    // check that if we have x>y that we
                    // if we have y>x or not
                    b = this.listSuccessionRelations.get(j).equals(successor, predecessor);
                    if (b==false) j++;
                }
                else {j++;}
            }
            if (b==false){
                        this.listCausalityRelations.add(new CausalityRelation(predecessor, successor));
            }
        }

    }



   /**
    * this method allows to check if we have
    * X#Y or not. If we have X#Y then it will return
    * true else it returns false
    * @param X
    * @param Y
    * @return
    */
    public boolean checkChoices(String X, String Y){
        // isChoise is true at the end if not(X>Y)
        // and not(Y>X) ie X#Y
        boolean isChoice = false ;
        // b1 is to check if we have X>Y
        // b1 == fasle means not(X>Y)
        boolean b1 = false ;
        // b2 is to check if we have Y<X
        // b2 == fasle means not(Y>X)
        boolean b2 = false ;

        int j = 0 ;

        while ((j<this.listSuccessionRelations.size()) && (b1==false) && (b2==false)){
            b1 = this.listSuccessionRelationsContains(X, Y);
            b2 = this.listSuccessionRelationsContains(Y, X);
            if ((b1==false) && (b2==false)) {
                j++;
            }
        }
        // if b1 and b2 are false at the end that means
        // that we have X#Y
        if ((b1==false) && (b2==false)){
            this.listChoiceRelations.add(new ChoiceRelation(X, Y));
            isChoice = true ;
        }
        return isChoice ;
    }


    /**
     * corresponds to a combination of the step 4 and 5 in the alpha algorithm
     * and it give directely the minimal causality relations. The reslut is put
     * into the attribute listCausalityRelationSets
     */
    public void buildCausalityRelationSetsList(){
        for (int i=0;i<listCausalityRelations.size();i++){
            String followedX = listCausalityRelations.get(i).getFollowedX();
            String followerY = listCausalityRelations.get(i).getFollowerY();
            CausalityRelationSetCouple cr = new CausalityRelationSetCouple();
            cr.addFollowedTask(followedX);
            cr.addFollowerTask(followerY);

            // the next "if" is only to avoid problems with the last member
            // of the list (listCausalityRelations)
            if (i!=(listCausalityRelations.size()-1)){
                // for the first member from i+1
                for (int j=i+1;j<listCausalityRelations.size();j++){
                    String s = listCausalityRelations.get(j).getFollowedX();
                    if (s.equals((String) followedX)){
                        String s1 = listCausalityRelations.get(j).getFollowerY();
                        // we check if s1#follower and if it is the case than
                        // we add it the followers list in cr (follower is in the list
                        // of followers of followedX
                        boolean b = true ;
                        int t = 0;
                        while ((t<cr.getListOfFollowers().size()) && (b==true)){
                            String follower = cr.getListOfFollowers().get(t);
                            if (!s1.equals((String) follower)){
                                 b = checkChoices(s1, follower) ;
                            }
                            else {
                                    b = false;
                            }
                            if (b==true){
                                t++;
                            }
                        }
                        // if s1 has a choice relation with all the already
                        // existing folloers than we add it to the list
                        if (b==true){
                            cr.addFollowerTask(s1);
                        }

                    }
                }
            }
            // after the j loop we have something that is like
            // ({A},{B,C}). So now we will try to find for exemple the D in tasks list
            // verifying D#A and D->B and D->C

            // for each second member :
            for (int k=0;k<cr.getListOfFollowers().size();k++){
                String s2 = cr.getListOfFollowers().get(k);
                // for the second member from the beginig but not the i
                // we look for the tasks a that have a choice relation
                // with all the members of the first member of followed
                // tasks and that have a causality relation with s2
                for (int l=0;l<this.listCausalityRelations.size();l++){
                    if (l!=i){
                        if(s2.equals((String) this.listCausalityRelations.get(l).getFollowerY())){
                            String s3 = this.listCausalityRelations.get(l).getFollowedX();
                            // we check here if s3 have a choice relation with
                            // all the members of the ListOfFollowed in 'cr'
                            boolean b1 = true ;
                            int t1 = 0;
                            while ((t1<cr.getListOfFollowed().size()) && (b1==true)){
                                String followed = cr.getListOfFollowed().get(t1);
                                if (!s3.equals((String) followed)){
                                    b1 = checkChoices(s3, followed) ;
                                }
                                else {
                                    b1 = false;
                                }
                                if (b1==true){
                                    t1++;
                                }
                            }
                            // if s1 has a choice relation with all the already
                            // existing folloers than we add it to the list
                            if (b1==true){
                                cr.addFollowedTask(s3);
                            }
                                }
                            }
                }
            }
            this.listCausalityRelationSets.add(cr);
        }
        // more selection : eliminate all the elements in the list
        // that are included on others
        int m = 0;
        while (m<listCausalityRelationSets.size()){
            int n = 0 ;
            boolean testG = false ;
            boolean testD = false ;
            while ((n<listCausalityRelationSets.size()) && (testG==false) && (testD==false)){
                if (n!=m){
                    testG = listCausalityRelationSets.get(n).getListOfFollowed().containsAll(listCausalityRelationSets.get(m).getListOfFollowed());
                    testD = listCausalityRelationSets.get(n).getListOfFollowers().containsAll(listCausalityRelationSets.get(m).getListOfFollowers());
                    // if we find that it is contained in an other element
                    // we eliminate it
                    if ((testG==true) && (testD==true)){
                        listCausalityRelationSets.remove(m);
                    }
                    else{
                        n++;
                    }
                }
                else {n++;}
            }
            // if we didn't delete the element (ie testG and testD are false) we increment m with 1
            // else we keep the same index (the same value of m
            if ((testG==false) || (testD==false)){
                m++;
            }
        }

    }

    /**
     * this method prints the set of the step 5 of the alpha
     * algorith (causality relations set)
     */
    public void printCausalityRelationsSet(){
        String s="causality relation sets : \n { \n";
        for (int i=0;i<this.listCausalityRelationSets.size();i++){
            s+="( "+ listCausalityRelationSets.get(i).toString()+" ) \n";
        }
        s+="} \n";
        System.out.println(s);
    }

    /**
     * print all the causal relations
     */
    public void printCausalityRelations(){
        String s=" causality relations : \n";
        for (int i=0;i<this.listCausalityRelations.size();i++){
            s+= listCausalityRelations.get(i).getFollowedX()+" -> "+listCausalityRelations.get(i).getFollowerY()+" \n";
        }
        System.out.println(s);
    }


    public void printSeccessionRelations(){
        String s=" succession relations : \n";
        for (int i=0;i<this.listSuccessionRelations.size();i++){
            s+= listSuccessionRelations.get(i).getPredecessorX()+" > "+listSuccessionRelations.get(i).getSuccessorY()+" \n";
        }
        System.out.println(s);
    }

    /**
     * this method allow to get all the places that we can
     * deduce from the log and put them in the attribute placesList
     * PS :  a place is "initial", "intermediary" or "final"
     */
    public void buildPlacesList(){
        Place firstPlace = new Place("P"+id_place.toString(), "initial");
        placesList.add(firstPlace);
        id_place++;

        for (int i=0;i<listCausalityRelationSets.size();i++){
            CausalityRelationSetCouple cr = listCausalityRelationSets.get(i);
            Place place = new Place("P"+id_place.toString(), "intermediary");
            for (int j=0;j<cr.getListOfFollowed().size();j++){
                place.addAFrom(cr.getListOfFollowed().get(j));
            }
            for (int j=0;j<cr.getListOfFollowers().size();j++){
                place.addATo(cr.getListOfFollowers().get(j));
            }
            placesList.add(place);
            id_place++;
        }

        Place finalPlace = new Place("P"+id_place.toString(), "final");
        placesList.add(finalPlace);
        id_place++;
    }

    public void printPlaces(){
        String s=" Places relations : \n";
        for (int i=0;i<this.placesList.size();i++){
            s+= placesList.get(i).toString()+"\n";
        }
        System.out.println(s);
    }



    /**
     * added method
     * this method allows to print in the screen the strings contained
     * in the list l
     * @param l
     */
    public void aficheListString(ArrayList<String> l){
        for (int i=0;i<l.size();i++){
            System.out.println(l.get(i));
        }
    }


    



}
